package org.diysearch.tools;

import java.net.URL;
import java.net.URLEncoder;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.htmlparser.Parser;
import org.htmlparser.beans.StringBean;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.util.NodeList;

import org.diysearch.exceptions.SiteNotFoundException;

public class HttpTools {
	private static final Log LOG = LogFactory.getLog(HttpTools.class);
	private static HttpClient client = null;
	private final static int SITE_NOT_FOUND = 404;
	private final static int SERVER_ERROR = 503;
	private final static int BAD_REQUEST = 501;

	static {
		client = new HttpClient();
	}

	public static String doGet(String url) throws Exception {
		String uri = null;
		StringBuffer qs = new StringBuffer();
		if (url.contains("?")) {
			URL u = new URL(url);
			// httplocalhost//solr/select/
			
			String[] pairs = u.getQuery().split("&");
			
			if (pairs.length > 0) {
				for (int i=0;i<pairs.length;i++) {
					String[] parts = pairs[i].split("=");
					qs.append(parts[0])
						.append("=")
						.append(URLEncoder.encode(parts[1],"UTF-8"))
						.append("&");
				}
			} else {
				String[] parts = u.getQuery().split("=");
				qs.append(parts[0])
					.append("=")
					.append(URLEncoder.encode(parts[1],"UTF-8"));
			}
			
			
			LOG.debug("query string: " + qs);
			StringBuffer sb = new StringBuffer();
			sb.append(u.getProtocol())
				.append("://")
				.append(u.getHost())
				.append(u.getPort() > 0 ? ":"+u.getPort() : "")
				.append(u.getPath());
			LOG.debug("URL: " + sb.toString());
			uri = sb.toString();
		} else {
			uri = url;
		}
		GetMethod method = new GetMethod(uri);
		if (qs != null) {	
			method.setQueryString(qs.toString());
		}
		String content = null;

		try {
			int status = client.executeMethod(method);
			switch (status) {
			case SITE_NOT_FOUND:
			case SERVER_ERROR:
			case BAD_REQUEST:
				throw new SiteNotFoundException("Site could not be loaded: "
						+ method.getURI());
			default:
				content = new String(method.getResponseBody());
			}

		} catch (Exception ex) {
			LOG.error(ex);
			throw new Exception("Something bad happened when fetching: " + method.getURI());
		} finally {
			method.releaseConnection();
		}

		return content;
	}

	/**
	 * Parse a site at the target URL. Basically what this does is, it finds all
	 * of the useful content within a site (as strings). It ignores things like
	 * CSS and JavaScript, and just gets at the textual content (which is what
	 * is important)
	 * 
	 * @param url -
	 *            of the site to be parsed
	 * @param tag -
	 *            a starting point within the HTML, example: BODY (which is most
	 *            useful). Default behavior is to just start at HTML (the whole
	 *            document)
	 * @return
	 * @throws Exception
	 */
	public static String parseSite(String url, String tag) throws Exception {
		Parser parser = new Parser(url);
		NodeList list = null;

		if (tag != null)
			list = parser.parse(new TagNameFilter(tag));
		else
			list = parser.parse(null);
		StringBean sb = new StringBean();
		list.visitAllNodesWith(sb);

		return sb.getStrings();
	}

	public static String parseSite(String url) throws Exception {
		return parseSite(url, null);
	}

	public static int doPost(String url, String data, String contentType,
			String charSet) throws Exception {
		PostMethod post = new PostMethod(url);
		StringRequestEntity re = new StringRequestEntity(data, contentType,
				charSet);
		post.setRequestEntity(re);
		int code = 0;

		try {
			code = client.executeMethod(post);
		} catch (Exception ex) {
			throw ex;
		} finally {
			if (post != null) {
				post.releaseConnection();
				post = null;
			}
			if (re != null) {
				re = null;
			}
		}

		return code;
	}
}
